#pragma once 

#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <queue>
#include <string>

namespace cp_thread_pool{
  const int g_num = 5;
  template<class T>
    class Thread_pool{
      private:
        int num_;//线程数
        std::queue<T> task_q;//任务队列
      
        pthread_mutex_t mtx;
        pthread_cond_t cond;
      public:
        Thread_pool(int num = g_num):num_(num){
          pthread_mutex_init(&mtx, nullptr);
          pthread_cond_init(&cond, nullptr);
        }
        ~Thread_pool(){
          pthread_mutex_destroy(&mtx);
          pthread_cond_destroy(&cond);
        }
        void InitThread_pool(){
          pthread_t tid;
          for(int i = 0; i < num_; i++){
            pthread_create(&tid, nullptr, Rountine, (void*)this);
          }
        }
        static void* Rountine(void* args){
          pthread_detach(pthread_self());
          Thread_pool<T>* tp = (Thread_pool<T>*)args;

          while(1){
            tp->lock();//给任务队列加锁
            while(tp->isEmpty()){
              tp->wait();
            }
            T t;
            tp->popTask(&t);
            tp->unlock();
            t.run();
          }
        }
        void lock(){
          pthread_mutex_lock(&mtx);
        }
        void unlock(){
          pthread_mutex_unlock(&mtx);
        }
        bool isEmpty(){
          return task_q.empty();
        }
        void wait(){
          pthread_cond_wait(&cond, &mtx);
        }
        void wakeUp(){
          pthread_cond_signal(&cond);
        }
        void pushTask(const T& in){
          lock();//给任务队列加锁
          task_q.push(in);
          unlock();
          wakeUp();
        }
        void popTask(T* out){
          *out = task_q.front();
          task_q.pop();
        }
    };
}
